﻿using Engine;
using Game;
using GameEntitySystem;
using SAGhoul.Blocks;
using System.Collections.Generic;
using TemplatesDatabase;

namespace SAGhoul.Tartareosity
{
	public class SubsystemAltarBlockBehavior : SubsystemBlockBehavior
	{
		public SubsystemWorld m_subsystemWorld;
		public SubsystemPortals m_subsystemPortals;
		public SubsystemTerrain m_subsystemTerrain;
		public SubsystemParticles m_subsystemParticles;
		public SubsystemPickables m_subsystemPickables;
		public SubsystemAudio m_subsystemAudio;

		public override int[] HandledBlocks => [];
		readonly Game.Random m_random = new();

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemWorld = Project.FindSubsystem<SubsystemWorld>(true);
			m_subsystemPortals = Project.FindSubsystem<SubsystemPortals>(true);
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
			m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(true);
			m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(true);
		}

		public override bool OnInteract(TerrainRaycastResult raycastResult, ComponentMiner componentMiner)
		{
			if (componentMiner == null)
				return false;
			int metalValue = typeof(BizarreMetalBlock).BlockIndex();
			int cellValue = raycastResult.Value, cellId = Terrain.ExtractContents(cellValue);
			if (cellId == typeof(TartareosityAltarBlock).BlockIndex())
			{
				bool chunked = TartareosityAltarBlock.IsChunked(cellValue);
				if (chunked)
				{
					m_subsystemPickables.AddPickable(metalValue, 1, raycastResult.HitPoint() + 0.5f * Vector3.UnitY, Vector3.UnitY, null);
					m_subsystemTerrain.ChangeCell(raycastResult.CellFace.X, raycastResult.CellFace.Y, raycastResult.CellFace.Z, TartareosityAltarBlock.SetChunked(cellValue, false));
				}
				else
				{
					if (Terrain.ExtractContents(componentMiner.ActiveBlockValue) == metalValue)
					{
						componentMiner.RemoveActiveTool(1);
						m_subsystemTerrain.ChangeCell(raycastResult.CellFace.X, raycastResult.CellFace.Y, raycastResult.CellFace.Z, TartareosityAltarBlock.SetChunked(cellValue, true));
						if (CheckPortalFrame(raycastResult.CellFace.Point, out var altars, out var waterStart, out var waterEnd, out string failReason))
						{
							//string txt = "Portal frame set!\naltars:\n";
							//foreach (var altar in altars)
							//{
							//	txt += $"{altar}\n";
							//}
							//Log.Warning($"{txt}waterStart:{waterStart}, waterEnd:{waterEnd}");
							foreach (var altar in altars)
							{//将祭坛重置为未激活状态
								int altarCellValue = m_subsystemTerrain.Terrain.GetCellValue(altar.X, altar.Y, altar.Z);
								if (Terrain.ExtractContents(altarCellValue) != typeof(TartareosityAltarBlock).BlockIndex() || !TartareosityAltarBlock.IsChunked(altarCellValue))
									continue;
								m_subsystemTerrain.ChangeCell(altar.X, altar.Y, altar.Z, TartareosityAltarBlock.SetChunked(altarCellValue, false));
								m_subsystemParticles.AddParticleSystem(new FireworksParticleSystem(new Vector3(altar) + new Vector3(0.5f, 1f, 0.5f), Color.Purple, FireworksBlock.Shape.Circle, 0.8f, 0.5f));
							}
							for (int x = waterStart.X; x <= waterEnd.X; x++)
							{
								for (int z = waterStart.Z; z <= waterEnd.Z; z++)
								{//移除水方块
									int waterCellValue = m_subsystemTerrain.Terrain.GetCellValue(x, waterStart.Y, z);
									if (Terrain.ExtractContents(waterCellValue) == typeof(WaterBlock).BlockIndex())
										m_subsystemTerrain.DestroyCell(0, x, waterStart.Y, z, 0, false, false);
								}
							}
							m_subsystemAudio.PlaySound("Audio/Tartareosity/Portal_Open", 0.8f, m_random.Float(-0.3f, 0.3f), (waterStart + waterEnd) / 2, 12f, autoDelay: false);
							Portal portal = new()
							{//添加传送门
								Min = new Vector3(waterStart),
								Max = new Vector3(waterEnd) + new Vector3(1f, 0.8f, 1f),
							};
							m_subsystemPortals.AddPortal(waterStart, portal);
						}
						//else if (!string.IsNullOrEmpty(failReason))
						//	componentMiner?.ComponentPlayer.ComponentGui.DisplaySmallMessage(failReason, Color.Yellow, true, true);
					}
					else
						componentMiner.ComponentPlayer?.ComponentGui?.DisplaySmallMessage($"Use {SAGhoulsManager.GetBlockDisplayName(typeof(BizarreMetalBlock))} to build Altars.", Color.White, true, true);
				}
				return true;
			}
			return false;
		}
		public bool CheckPortalFrame(Point3 startPoint, out List<Point3> altars, out Point3 waterStart, out Point3 waterEnd, out string failReason)
		{
			altars = [];
			waterStart = Point3.Zero;
			waterEnd = Point3.Zero;
			failReason = string.Empty;

			// 检查起始点基座结构
			if (!GetIsChunkedAltar(startPoint)
				|| GetCellContents(startPoint - Point3.UnitY) != typeof(TartareosityBasaltBlock).BlockIndex()
				|| GetCellContents(startPoint - Point3.UnitY * 2) != typeof(TartareosityRockBlock).BlockIndex())
			{
				failReason = "No available base blocks found";
				return false;
			}
			int minFrameSize = 4, maxFrameSize = 16;//外边框尺寸

			Point3 step1RockPoint = startPoint - Point3.UnitY * 2;
			int? xAxisLength = CheckDirectionFromRock(step1RockPoint, Point3.UnitX, minFrameSize, maxFrameSize, out var altarPoint1);//检查x轴正方向是否有祭坛
			int? xAxis2Length = null;//检查x轴负方向是否有祭坛
			if (xAxisLength.HasValue)
			{
				altars.Add(altarPoint1);
			}
			else
			{//仅在x轴正方向没有祭坛时检查负方向
				xAxis2Length = CheckDirectionFromRock(step1RockPoint, -Point3.UnitX, minFrameSize, maxFrameSize, out var altarPoint2);
				if (xAxis2Length.HasValue)
					altars.Add(altarPoint2);
				else
				{//x轴正负方向都没有，检查失败
					failReason = "Check your frame:\nNeither the positive nor negative directions of the x-axis meet the requirements";
					return false;
				}
			}

			Point3 step2RockPoint = step1RockPoint + (xAxisLength.HasValue ? Point3.UnitX * xAxisLength.Value : -Point3.UnitX * xAxis2Length.Value);
			int? zAxisLength = CheckDirectionFromRock(step2RockPoint, Point3.UnitZ, minFrameSize, maxFrameSize, out var altarPoint3);//检查z轴正方向是否有祭坛
			int? zAxis2Length = null;//检查z轴负方向是否有祭坛
			if (zAxisLength.HasValue)
			{
				altars.Add(altarPoint3);
			}
			else
			{//仅在z轴正方向没有祭坛时检查负方向
				zAxis2Length = CheckDirectionFromRock(step2RockPoint, -Point3.UnitZ, minFrameSize, maxFrameSize, out var altarPoint4);
				if (zAxis2Length.HasValue)
					altars.Add(altarPoint4);
				else
				{//z轴正负方向都没有，检查失败
					failReason = "Check your frame:\nNeither the positive nor negative directions of the Z-axis meet the requirements";
					return false;
				}
			}

			Point3 step3RockPoint = step2RockPoint + (zAxisLength.HasValue ? Point3.UnitZ * zAxisLength.Value : -Point3.UnitZ * zAxis2Length.Value);
			int? xAxisRELength = null;
			for (int i = 1; i < maxFrameSize; i++)
			{//第3步方向固定，与第1步得到的x轴方向结果相反。无需再向两个方向检测
				Point3 checkPoint = step3RockPoint + new Point3(i, 0, 0) * (xAxisLength.HasValue ? -1 : 1);
				if (GetCellContents(checkPoint) == typeof(TartareosityRockBlock).BlockIndex())
				{
					if (i < minFrameSize - 1)
						break;//长度不足，该方向不满足条件
					if (GetCellContents(checkPoint + Point3.UnitY) == typeof(TartareosityBasaltBlock).BlockIndex()
						&& GetIsChunkedAltar(checkPoint + Point3.UnitY * 2))
					{//向上检查玄武岩柱和祭坛完整性，若成功则记录长度和祭坛位置
						xAxisRELength = i;
						altars.Add(checkPoint + Point3.UnitY * 2);
						break;
					}
				}
				else if (GetCellContents(checkPoint) != typeof(TartareosityDirtBlock).BlockIndex())//即不是岩石也不是土壤，该方向不满足条件
					break;
			}
			if (!xAxisRELength.HasValue || (xAxisRELength.Value != (xAxisLength ?? -1) && xAxisRELength.Value != (xAxis2Length ?? -1)))
			{//第3步检测失败或长度与第1步不一致，检查失败
				failReason = "Check your frame:\nThe length of the two sides in the x-axis direction is asymmetrical";
				return false;
			}

			Point3 step4RockPoint = step3RockPoint + (xAxisLength.HasValue ? -Point3.UnitX * xAxisLength.Value : Point3.UnitX * xAxis2Length.Value);
			int? zAxisRELength = null;
			for (int i = 1; i < maxFrameSize; i++)
			{//第4步方向固定，与第2步得到的z轴方向结果相反。无需再向两个方向检测
				Point3 checkPoint = step4RockPoint + new Point3(0, 0, i) * (zAxisLength.HasValue ? -1 : 1);
				if (GetCellContents(checkPoint) == typeof(TartareosityRockBlock).BlockIndex())
				{
					if (i < minFrameSize - 1)
						break;//长度不足，该方向不满足条件
					if (GetCellContents(checkPoint + Point3.UnitY) == typeof(TartareosityBasaltBlock).BlockIndex()
						&& GetIsChunkedAltar(checkPoint + Point3.UnitY * 2))
					{//向上检查玄武岩柱和祭坛完整性，若成功则记录长度和祭坛位置
						zAxisRELength = i;
						altars.Add(checkPoint + Point3.UnitY * 2);
						break;
					}
				}
				else if (GetCellContents(checkPoint) != typeof(TartareosityDirtBlock).BlockIndex())//即不是岩石也不是土壤，该方向不满足条件
					break;
			}
			if (!zAxisRELength.HasValue || (zAxisRELength.Value != (zAxisLength ?? -1) && zAxisRELength.Value != (zAxis2Length ?? -1)))
			{//第4步检测失败或长度与第2步不一致，检查失败
				failReason = "Check your frame:\nThe length of the two sides in the Z-axis direction is asymmetrical";
				return false;
			}

			//通过框架检查，接下来检查水的完整性
			Point3 min = Point3.Min(Point3.Min(step1RockPoint, step2RockPoint), Point3.Min(step3RockPoint, step4RockPoint)) + new Point3(1, 0, 1);
			for (int i = 0; i < xAxisRELength - 1; i++)
			{
				for (int j = 0; j < zAxisRELength - 1; j++)
				{
					Point3 checkPoint = min + new Point3(i, 0, j);
					if (!GetIsFullWater(checkPoint))
					{
						failReason = $"{checkPoint} is not the water that meets the requirements";
						return false;//框架中任何一格不是水，检查失败
					}
				}
			}
			waterStart = min;
			waterEnd = min + new Point3(xAxisRELength.Value - 2, 0, zAxisRELength.Value - 2);
			return true;
		}
		int? CheckDirectionFromRock(Point3 point, Point3 direction, int minFrameSize, int maxFrameSize, out Point3 altarPoint)
		{
			int? axisLength = null;
			altarPoint = Point3.Zero;
			for (int i = 1; i < maxFrameSize; i++)
			{
				Point3 checkPoint = point + direction * i;
				if (GetCellContents(checkPoint) == typeof(TartareosityRockBlock).BlockIndex())
				{
					if (i < minFrameSize - 1)
						break;//该方向长度不足，检查失败
					if (GetCellContents(checkPoint + Point3.UnitY) == typeof(TartareosityBasaltBlock).BlockIndex()
						&& GetIsChunkedAltar(checkPoint + Point3.UnitY * 2))
					{//向上检查玄武岩柱和祭坛完整性，若成功则记录长度和祭坛位置
						axisLength = i;
						altarPoint = checkPoint + Point3.UnitY * 2;
						break;
					}
				}
				else if (GetCellContents(checkPoint) != typeof(TartareosityDirtBlock).BlockIndex())//即不是岩石也不是土壤，检查失败
					break;
			}
			return axisLength;
		}
		int GetCellContents(Point3 point)
		{
			return m_subsystemTerrain.Terrain.GetCellContents(point.X, point.Y, point.Z);
		}
		bool GetIsChunkedAltar(Point3 point)
		{
			int cellValue = m_subsystemTerrain.Terrain.GetCellValue(point.X, point.Y, point.Z);
			if (Terrain.ExtractContents(cellValue) == typeof(TartareosityAltarBlock).BlockIndex())
			{
				return TartareosityAltarBlock.IsChunked(cellValue);
			}
			return false;
		}
		bool GetIsFullWater(Point3 point)
		{
			int cellValue = m_subsystemTerrain.Terrain.GetCellValue(point.X, point.Y, point.Z), cellId = Terrain.ExtractContents(cellValue);
			if (cellId == typeof(WaterBlock).BlockIndex())
			{
				return FluidBlock.GetLevel(Terrain.ExtractData(cellValue)) == 0;
			}
			return false;
		}

	}
}
